package tail

import (
	"log/lg"
	"log/nacos"
	"time"
)

//管理者的结构体
type tailMng struct {
	conf        []*nacos.Conf        //存储第一次配置,用于后面作用于配置对比
	TskMap      map[string]*TailTask //用字典存储在后台运行的携程实例,方便 增 删
	newChanConf chan []*nacos.Conf   //接收新的配置,存在通道中,后台执行一个监听携程,作用于配置的热更新
}

var taskMng *tailMng

// Init 初始化管理者构造函数
func Init(logConf []*nacos.Conf) {
	taskMng = &tailMng{
		conf:        logConf,                        //存取当前从etcd获取的日志配置
		TskMap:      make(map[string]*TailTask, 16), //初始化,最多收集16个配置收集
		newChanConf: make(chan []*nacos.Conf),       //初始化无缓冲区的配置通道
	}
	//哪去配置,然后轮询读取,创建实例
	//轮询获取多个配置
	for _, v := range logConf {
		//初始化实例
		tailObj := NewTailTask(v.Path, v.Topic)
		lg.Log.Info("获取配置成功,成功创建监听日志实例:主题:", v.Topic, ",路径:", v.Path)
		//记录创建成功的实例, 记录在管理者的字典里面
		//把初始化的tail实例记录进字典里面
		mk := v.Path + "_" + v.Topic
		taskMng.TskMap[mk] = tailObj
	}
	//后台运行配置监听配置变化
	go taskMng.run()
}

//监听通道中的新配置,有变动,重新构造
func (t *tailMng) run() {
	for {
		select {
		//从通道中拿取最新的配置,无缓冲区
		case newConf := <-t.newChanConf:
			//直接删除所有的旧配置，添加新的配置
			for _, c1 := range t.conf { // 从原来的配置中依次拿出配置项
				// 把c1对应的这个tailObj给停掉
				mk := c1.Path + "_" + c1.Topic
				lg.Log.Info("删除一个tail配置成功:", mk)
				//t.tskMap[mk] ==> tailObj
				t.TskMap[mk].cancelFunc()

			}
			//添加新的配置
			for _, conf := range newConf {
				mk := conf.Path + "_" + conf.Topic
				lg.Log.Info("添加一个新的路径配置:", mk)
				tailObj := NewTailTask(conf.Path, conf.Topic)
				//把初始化的tail实例记录进字典里面
				taskMng.TskMap[mk] = tailObj

			}

			//配置变更
		default:
			time.Sleep(time.Second)

		}
	}

}

// TailChanNewConf 暴露出去的通道函数 推送最新的配置给tail管理者
func TailChanNewConf() chan<- []*nacos.Conf {
	return taskMng.newChanConf
}
